package org.colcon.web.model;

import java.util.HashMap;
import java.util.Map;

import org.colcon.web.model.framework.IContainer;
import org.colcon.web.model.framework.IItem;
import org.colcon.web.model.framework.ITitle;

public class CLI 
{
	public static final String
	
		NULL = "null",
		DELIMETER = " ",
		ARG_TAG = "-",
	
		USERS = "users",
		GROUPS = "groups",
		
		// groups
		CONTRIBUTOR_CONGRESS = "contributor_congress",
		GROUP_CONGRESS = "group_congress",
		USER_CONGRESS = "user_congress",
		
		// users
		ADMIN = "admin",
		
		// commands
		HELP = "help",
		GET = "get",
		SET = "set",
		ADD = "add",
		REMOVE = "remove",
		OPEN = "open",
		ASSIGN = "assign",
		CREATE_GROUP =  "create_group",
		CREATE_TITLE =  "create_title",
		
		// command arguments
		CMD = "cmd",
		PATH = "path",
		ID = "id",
		TEXT = "text",
		TYPE = "type",
		USER = "user",
		GROUP = "group";
	
	public static Map<String, String> parse(String cmd)
	{
		if(cmd == null)
			return null;
		
		Map<String, String> args = new HashMap<String, String>();
		
		if(cmd.length() == 0)
			return args;
		
		String[] array = cmd.split(DELIMETER);
		
		if(array.length > 0 && array[0] != null && 
				array[0].length() > 0)
			args.put(CMD, array[0]);
		
		if(array.length > 1 && array[1] != null && 
				array[1].length() > 0 && !array[1].startsWith(ARG_TAG))
			args.put(PATH, array[1]);
		
		//TODO: parse { }
		
		for(int i = 1; i < array.length; i++)
		{
			String str = array[i];
			
			if(str.startsWith(ARG_TAG))
			{
				String key = str.substring(1);
				if(i + 1 < array.length && !array[i + 1].startsWith(ARG_TAG))
				{
					args.put(key, array[i + 1]);
					i++;
				}
				else
				{
					args.put(key, "");
				}
			}
		}
		
		return args;
	}
	
	public static String execute(String cmd)
	{
		return execute(parse(cmd));
	}
	
	public static String execute(Map<String, String> args)
	{
		String cmd = args.get(CMD);
		
		if(cmd == null || cmd.length() == 0)
			return "invalid command";
		
		if(cmd.equals(NULL))
		{
			return NULL;
		}
		else if(cmd.equals(HELP))
		{
			return getHelpString();
		}
		else if(cmd.equals(GET))
		{
			String path = args.get(PATH);
			
			if(!Model.has(path))
				return "item " + path + " not found";
			
			IItem item = Model.get(path);
			
			return item.getId() + ": " + item.getText();
		}
		else if(cmd.equals(ADD))
		{
			String path = args.get(PATH);
			
			if(!Model.has(path))
				return "container " + path + " not found";
			
			if(!Model.get(path).isContainer())
				return "item " + path + " is not a container";
			
			String id = args.get(ID);
			
			if(Model.has(path, id))
				return "item " + id + " already exists in " + path;
			
			String type = args.get(TYPE);
			
			if(type == null)
				return "missing argument -type";
			
			IItem item = parseItem(args);
			
			if(item == null)
				return "invalid item arguments";
			
			Model.add(path, item);

			return "item " + id + " successfully added to " + path;
		}
		else if(cmd.equals(REMOVE))
		{
			String path = args.get(PATH);
			
			if(!Model.has(path))
				return "item " + path + " not found";
			
			boolean result = Model.remove(path);
			
			if(!result)
				return "failed to remove item " + path;
			
			return "item " + path + " successfully removed";
		}
		else if(cmd.equals(OPEN))
		{
			String path = args.get(PATH);
			
			if(path == null)
				path = "";
			
			if(!Model.has(path))
				return "item " + path + " not found";
			
			IItem item = Model.get(path);
			
			if(!item.isContainer())
				return "item " + path + " is not a container";
			
			String output = "\n" + item.getId() + ": " + item.getText() + "\n\n";
			
			for(IItem child : ((IContainer)item).getChildren())
				output += "     " + child.getId() + ": " + child.getText() + "\n";
			
			return output;
		}
		else if(cmd.equals(ASSIGN))
		{
			String path = args.get(PATH);
			String user = args.get(USER);
			
			if(!Model.has(path))
				return "item " + path + " not found";
			
			if(!Model.has(user))
				return "item " + user + " not found";
			
			IItem item = Model.get(path);
			
			if(!(item instanceof ITitle))
				return "item " + path + " is not a title";
			
			boolean result = Model.assignTitle(path, user);
			
			if(result)
				return "title " + path + " assigned to user " + user;
			else
				return "failed to assign title";
		}
		else if(cmd.equals(CREATE_GROUP))
		{
			return execute("add groups" + " -type group -id " + args.get(ID) + " -text " + args.get(TEXT));
		}
		else if(cmd.equals(CREATE_TITLE))
		{
			return execute("add groups/" + args.get(GROUP) + "/titles -type title -id " + args.get(ID) + " -text " + args.get(TEXT));
		}

		return "command " + cmd + " not found";
	}
	
	public static IItem parseItem(Map<String, String> args)
	{
		//TODO: validate args
		
		String type = args.get(TYPE).toLowerCase();
		
		//TODO: replace string literals with constants
		
		if(type.equals("user"))
		{
			return new User(args);
		}
		else if(type.equals("group"))
		{
			return new Group(args);
		}
		else if(type.equals("law"))
		{
			return new Law(args);
		}
		else if(type.equals("title"))
		{
			return new Title(args);
		}
		else if(type.equals("vote"))
		{
			return new Vote(args);
		}
		else if(type.equals("proposal"))
		{
			return new Proposal(args);
		}
		
		return null;
	}
	
	public static String getHelpString()
	{
		return
				"get -path [item_path]\n" +
				"open -path [item_path]\n" +
				"remove -path [item_path]\n" +
				"add -path [item_path] -item_type [item_type] [item_args]\n" +
				"create_user -id [group_id]\n" +
				"create_group -id [group_id] -text [group_text]\n" +
				"assign_title -path [title_path] -user [user_id]\n";
	}
}
